#ifndef __DRIVER_SDCARD_H
#define __DRIVER_SDCARD_H
#include "types.h"

//#define CONFIG_APP_SDCARD

//#define SDCARD_DEBUG

#ifdef SDCARD_DEBUG
#define SDCARD_PRT os_printf
#define SDCARD_WARN os_printf
#define SDCARD_FATAL os_printf
#else
#define SDCARD_PRT os_null_printf
#define SDCARD_WARN os_null_printf
#define SDCARD_FATAL os_printf
#endif

// SDCARD REG
#define SDCARD_BASE_ADDR (0x01878000)

#define REG_SDCARD_CMD_SEND_CTRL (SDCARD_BASE_ADDR + 0 * 4)
#define SDCARD_CMD_SEND_CTRL_CMD_START (1 << 0)
#define SDCARD_CMD_SEND_CTRL_CMD_FLAGS_MASK (0x7)
#define SDCARD_CMD_SEND_CTRL_CMD_FLAGS_POSI (1)
#define SDCARD_CMD_SEND_CTRL_CMD_INDEX_MASK (0x3f)
#define SDCARD_CMD_SEND_CTRL_CMD_INDEX_POSI (4)

#define REG_SDCARD_CMD_SEND_AGUMENT (SDCARD_BASE_ADDR + 1 * 4)
#define REG_SDCARD_CMD_RSP_TIMER (SDCARD_BASE_ADDR + 2 * 4)

#define REG_SDCARD_DATA_REC_CTRL (SDCARD_BASE_ADDR + 3 * 4)
#define SDCARD_DATA_REC_CTRL_DATA_EN (1 << 0)
#define SDCARD_DATA_REC_CTRL_DATA_STOP_EN (1 << 1)
#define SDCARD_DATA_REC_CTRL_DATA_BUS (1 << 2)
#define SDCARD_DATA_REC_CTRL_DATA_MUL_BLK (1 << 3)
#define SDCARD_DATA_REC_CTRL_BLK_SIZE_MASK (0xfff)
#define SDCARD_DATA_REC_CTRL_BLK_SIZE_POSI (4)
#define SDCARD_DATA_REC_CTRL_DATA_WR_DATA_EN (1 << 16)
#define SDCARD_DATA_REC_CTRL_DATA_BYTE_SEL (1 << 17)

#define REG_SDCARD_DATA_REC_TIMER (SDCARD_BASE_ADDR + 4 * 4)
#define REG_SDCARD_CMD_RSP_AGUMENT0 (SDCARD_BASE_ADDR + 5 * 4)
#define REG_SDCARD_CMD_RSP_AGUMENT1 (SDCARD_BASE_ADDR + 6 * 4)
#define REG_SDCARD_CMD_RSP_AGUMENT2 (SDCARD_BASE_ADDR + 7 * 4)
#define REG_SDCARD_CMD_RSP_AGUMENT3 (SDCARD_BASE_ADDR + 8 * 4)

#define REG_SDCARD_CMD_RSP_INT_SEL (SDCARD_BASE_ADDR + 9 * 4)
#define SDCARD_CMDRSP_NORSP_END_INT (1 << 0)
#define SDCARD_CMDRSP_RSP_END_INT (1 << 1)
#define SDCARD_CMDRSP_TIMEOUT_INT (1 << 2)
#define SDCARD_CMDRSP_DATA_REC_END_INT (1 << 3)
#define SDCARD_CMDRSP_DATA_WR_END_INT (1 << 4)
#define SDCARD_CMDRSP_DATA_TIME_OUT_INT (1 << 5)
#define SDCARD_CMDRSP_RX_FIFO_NEED_READ (1 << 6)
#define SDCARD_CMDRSP_TX_FIFO_NEED_WRITE (1 << 7)
#define SDCARD_CMDRSP_RX_OVERFLOW (1 << 8)
#define SDCARD_CMDRSP_TX_FIFO_EMPTY (1 << 9)
#define SDCARD_CMDRSP_CMD_CRC_OK (1 << 10)
#define SDCARD_CMDRSP_CMD_CRC_FAIL (1 << 11)
#define SDCARD_CMDRSP_DATA_CRC_OK (1 << 12)
#define SDCARD_CMDRSP_DATA_CRC_FAIL (1 << 13)
#define SDCARD_CMDRSP_RSP_INDEX (0x3f << 14)
#define SDCARD_CMDRSP_WR_STATU (0x7 << 20)
#define SDCARD_CMDRSP_DATA_BUSY (0x1 << 23)

#define REG_SDCARD_CMD_RSP_INT_MASK (SDCARD_BASE_ADDR + 10 * 4)
#define SDCARD_CMDRSP_NORSP_END_INT_MASK (1 << 0)
#define SDCARD_CMDRSP_RSP_END_INT_MASK (1 << 1)
#define SDCARD_CMDRSP_TIMEOUT_INT_MASK (1 << 2)
#define SDCARD_CMDRSP_DATA_REC_END_INT_MASK (1 << 3)
#define SDCARD_CMDRSP_DATA_WR_END_INT_MASK (1 << 4)
#define SDCARD_CMDRSP_DATA_TIME_OUT_INT_MASK (1 << 5)
#define SDCARD_CMDRSP_RX_FIFO_NEED_READ_MASK (1 << 6)
#define SDCARD_CMDRSP_TX_FIFO_NEED_WRITE_MASK (1 << 7)
#define SDCARD_CMDRSP_RX_OVERFLOW_MASK (1 << 8)
#define SDCARD_CMDRSP_TX_FIFO_EMPTY_MASK (1 << 9)

#define REG_SDCARD_WR_DATA_ADDR (SDCARD_BASE_ADDR + 11 * 4)
#define REG_SDCARD_RD_DATA_ADDR (SDCARD_BASE_ADDR + 12 * 4)

#define REG_SDCARD_FIFO_THRESHOLD (SDCARD_BASE_ADDR + 13 * 4)
#define SDCARD_FIFO_RX_FIFO_THRESHOLD_MASK (0xff)
#define SDCARD_FIFO_RX_FIFO_THRESHOLD_POSI (0)
#define SDCARD_FIFO_TX_FIFO_THRESHOLD_MASK (0xff)
#define SDCARD_FIFO_TX_FIFO_THRESHOLD_POSI (8)
#define SDCARD_FIFO_RX_FIFO_RST (1 << 16)
#define SDCARD_FIFO_TX_FIFO_RST (1 << 17)
#define SDCARD_FIFO_RXFIFO_RD_READY (1 << 18)
#define SDCARD_FIFO_TXFIFO_WR_READY (1 << 19)
#define SDCARD_FIFO_SD_STA_RST (1 << 20)
#define SDCARD_FIFO_SD_RATE_SELECT_POSI (21)
#define SDCARD_FIFO_SD_RATE_SELECT_MASK (0x3)
#define SDCARD_FIFO_SD_CLK_REC_SEL (1 << 25)

//SDcard select SD or SD1
#define SD_HOST_INTF 0  /*select gpio8/9/10/35/34/36*/
#define SD1_HOST_INTF 1 /*select gpio37/38/39/35/34/36*/
#define CFG_SD_HOST_INTF SD1_HOST_INTF

// SDcard defination
/* Exported types ------------------------------------------------------------*/
typedef enum
{
    SD_OK = 0,
    SD_CMD_CRC_FAIL = (1),    /*!< Command response received (but CRC check failed) */
    SD_DATA_CRC_FAIL = (2),   /*!< Data bock sent/received (CRC check Failed) */
    SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */
    SD_DATA_TIMEOUT = (4),    /*!< Data time out */

    SD_INVALID_VOLTRANGE,
    SD_R5_ERROR,         /* A general or an unknown error occurred during the operation */
    SD_R5_ERR_FUNC_NUMB, /* An invalid function number was requested */
    SD_R5_OUT_OF_RANGE,  /*The command's argument was out of the allowed range for this card*/
    SD_ERROR,
    SD_ERR_LONG_TIME_NO_RESPONS,
    SD_ERR_CMD41_CNT = 0xfffe
} SDIO_Error;

#define SD_CMD_NORESP 0
#define SD_CMD_SHORT (CMD_FLAG_RESPONSE | CMD_FLAG_CRC_CHECK)
#define SD_CMD_LONG (CMD_FLAG_RESPONSE | CMD_FLAG_LONG_CMD | CMD_FLAG_CRC_CHECK)

#define SD_CMD_RSP (SDCARD_CMDRSP_NORSP_END_INT | SDCARD_CMDRSP_RSP_END_INT | SDCARD_CMDRSP_TIMEOUT_INT | SDCARD_CMDRSP_CMD_CRC_FAIL)

#define SD_DATA_RSP (SDCARD_CMDRSP_DATA_REC_END_INT | SDCARD_CMDRSP_DATA_CRC_FAIL | SDCARD_CMDRSP_DATA_WR_END_INT | SDCARD_CMDRSP_DATA_TIME_OUT_INT)

#define SD_DATA_DIR_RD 0
#define SD_DATA_DIR_WR 1

#define OCR_MSK_BUSY 0x80000000              // Busy flag
#define OCR_MSK_HC 0x40000000                // High Capacity flag
#define OCR_MSK_VOLTAGE_3_2V_3_3V 0x00100000 // Voltage 3.2V to 3.3V flag
#define OCR_MSK_VOLTAGE_ALL 0x00FF8000       // All Voltage flag

#define SD_DEFAULT_OCR (OCR_MSK_VOLTAGE_ALL | OCR_MSK_HC)

#define SD_MAX_VOLT_TRIAL (0xFF)

#define SD_DEFAULT_BLOCK_SIZE 512
#define SDCARD_TX_FIFO_THRD (0x01) // 16byte
#define SDCARD_RX_FIFO_THRD (0x01)

#define CLK_26M 0
#define CLK_13M 1
#define CLK_6_5M 2
#define CLK_3_25M 3

#define CMD_FLAG_RESPONSE 0x01
#define CMD_FLAG_LONG_CMD 0x02
#define CMD_FLAG_CRC_CHECK 0x04
#define CMD_FLAG_MASK 0x07

#define DEF_LOW_SPEED_CMD_TIMEOUT 1000 //200k -- about 5us (500ms)
#define DEF_LOW_SPEED_DATA_TIMEOUT 100000

#define DEF_HIGH_SPEED_CMD_TIMEOUT 10000 //26M - about 40ns (800ms)
#define DEF_HIGH_SPEED_DATA_TIMEOUT 1000 //about 400ms

#define DEF_CMD_TIME_OUT 0x100
#define DEF_DATA_TIME_OUT 0x3000000

#define SDIO_RD_DATA 0
#define SDIO_WR_DATA 1
#define SDIO_RD_AF_WR 3

#define SDIO_DEF_LINE_MODE 4
#define SDIO_DEF_WORK_CLK 13

#define SD_CLK_PIN_TIMEOUT1 0x1000
#define SD_CLK_PIN_TIMEOUT2 0x8000
#define SD_CARD_OFFLINE 0
#define SD_CARD_ONLINE 1

//#define CONFIG_SDCARD_BUSWIDTH_4LINE

/* Standard sd  commands (  )           type  argument     response */
#define GO_IDLE_STATE 0 /* bc                          */
#define ALL_SEND_CID 2
#define SEND_RELATIVE_ADDR 3 /* ac   [31:16] RCA        R6  */
#define IO_SEND_OP_COND 5    /* ac                      R4  */
#define SWITCH_FUNC 6
#define SELECT_CARD 7  /* ac   [31:16] RCA        R7  */
#define SEND_IF_COND 8 /* adtc                    R1  */
#define SEND_CSD 9
#define SEND_STATUS 13
#define READ_SINGLE_BLOCK 17
#define WRITE_BLOCK 24
#define SD_APP_OP_COND 41
#define IO_RW_DIRECT 52   /* ac   [31:0] See below   R5  */
#define IO_RW_EXTENDED 53 /* adtc [31:0] See below   R5  */
#define APP_CMD 55

#define R5_COM_CRC_ERROR (1 << 15)   /* er, b */
#define R5_ILLEGAL_COMMAND (1 << 14) /* er, b */
#define R5_ERROR (1 << 11)           /* erx, c */
#define R5_FUNCTION_NUMBER (1 << 9)  /* er, c */
#define R5_OUT_OF_RANGE (1 << 8)     /* er, c */
#define R5_STATUS(x) (x & 0xCB00)
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */

/*STM32 register bit define*/
#define SDIO_ICR_MASK 0x5FF
#define SDIO_STATIC_FLAGS ((uint32_t)0x000005FF)
#define SDIO_FIFO_ADDRESS ((uint32_t)0x40018080)

#define OCR_MSK_BUSY 0x80000000        // Busy flag
#define OCR_MSK_HC 0x40000000          // High Capacity flag
#define OCR_MSK_VOLTAGE_ALL 0x00FF8000 // All Voltage flag

#define SD_DEFAULT_OCR (OCR_MSK_VOLTAGE_ALL | OCR_MSK_HC)

//#define SD_CLK_PIN                              34
#define REG_A2_CONFIG ((0x0802800) + 50 * 4)

/*typedef enum
{
    SD_CARD_IDLE                 = 0,
    SD_CARD_READY                = 1,
    SD_CARD_IDENTIFICATION       = 2,
    SD_CARD_STANDBY              = 3,
    SD_CARD_TRANSFER             = 4,
    SD_CARD_SENDING              = 5,
    SD_CARD_RECEIVING            = 6,
    SD_CARD_PROGRAMMING          = 7,
    SD_CARD_DISCONNECTED         = 8,
    SD_CARD_ERROR                = 0xff
} SDCardState;*/

enum
{
    SD_ERR_NONE = 0,
    SD_ERR_CMD_TIMEOUT = 1,
    SD_ERR_CMD_CRC_FAIL = 2,
    SD_ERR_DATA_TIMEOUT = 3,
    SD_ERR_DATA_CRC_FAIL = 4

};

#define SD_CMD_FLAG_RESPONSE 0x01
#define SD_CMD_FLAG_LONG_CMD 0x02
#define SD_CMD_FLAG_CRC_CHECK 0x04
#define DEFAULT_CMD_TIME_OUT 0x300000
#define DEFAULT_DATA_TIME_OUT 0x300000

typedef struct sdio_command
{
    uint32_t index;
    uint32_t arg;
    uint32_t flags; /* expected response type */
    uint32_t timeout;
    uint32_t resp[4];
    void *data;     /* data segment associated with cmd */
    SDIO_Error err; /* command error */
} SDIO_CMD_S, *SDIO_CMD_PTR;

typedef void (*SD_DETECT_FUN)(void);

typedef struct _sdcard_
{
    uint32_t total_block;
    uint16_t block_size;
    uint16_t card_rca;
    uint16_t init_flag;
    uint16_t Addr_shift_bit;
    SD_DETECT_FUN detect_func;
} SDCARD_S, *SDCARD_PTR;

SDIO_Error SD_init(void);
void sdcard_uninitialize(void);
int sdcard_get_size(void);
void sd_detect_init(void);
uint8_t sd_is_attached(void);
void app_sd_init(void);

void sdcard_get_card_info(SDCARD_S *card_info);
SDIO_Error sdcard_read_single_block(uint8_t *readbuff, uint32_t readaddr, uint32_t blocksize);
SDIO_Error sdcard_read_multi_block(uint8_t *read_buff, int first_block, int block_num);
SDIO_Error sdcard_write_single_block(uint32_t *writebuff, uint32_t writeaddr);
SDIO_Error sdcard_write_multi_block(uint8_t *write_buff, uint32_t first_block, uint32_t block_num);
void sd_detect_fun(void);

void sd_test_write(void);
void sd_test_write1(void);

void app_sd_scanning(void);
void sdcard_idle(char enable);
int sdcard_get_block_size(void);

void clr_sd_noinitial_flag(void);
void clear_sd_attached(void);
void clear_sd_detached(void);
#endif
